#include "../exercise.h"


// READ: `namespace` <https://en.cppreference.com/w/cpp/language/namespace>


// 命名空间定义
namespace MyNamespace {
    int value = 10;
    int add(int a, int b) {
        return a + b;
    }
}

// 嵌套命名空间
namespace Outer {
    namespace Inner {
        std::string message = "Nested namespace";
    }
}

// 未命名命名空间 (行为类似静态局部变量)
namespace {
    double pi = 3.14159;
}

// 命名空间别名
namespace OIN = Outer::Inner;

// 另一个用于演示冲突解决的命名空间
namespace Conflict {
    int value = 20;
}

int main(int argc, char **argv) {
    // 练习 1: 使用作用域解析运算符访问成员
    {
        ASSERT(MyNamespace::value == 10, "从 MyNamespace 访问 value");
        ASSERT(MyNamespace::add(5, 3) == 8, "从 MyNamespace 调用 add 函数");
    }
    
    // 练习 2: 使用 `using` 声明
    {
        using MyNamespace::value;
        ASSERT(value == 10, "使用 using 声明后访问 value");
        // ASSERT(add(1, 2) == 3, "如果没有 `using MyNamespace::add;` 或 `MyNamespace::`，这应该会失败"); // 取消注释测试一下
    }
    
    // 练习 3: 使用 `using` 指令
    {
        using namespace MyNamespace;
        ASSERT(value == 10, "在带有 using 指令的代码块内访问 value");
        ASSERT(add(10, 5) == 15, "在带有 using 指令的代码块内调用 add 函数");
    }
    // ASSERT(add(1, 2) == 3, "这应该在代码块外失败"); // 取消注释测试一下

    // 练习 4: 嵌套命名空间
    ASSERT(Outer::Inner::message == "Nested namespace", "从嵌套命名空间访问 message");

    // 练习 5: 命名空间别名
    ASSERT(OIN::message == "Nested namespace", "使用命名空间别名访问 message");

    // 练习 6: 未命名命名空间
    // 未命名命名空间提供内部链接。成员可以在同一翻译单元中直接访问。
    ASSERT(pi > 3.14 && pi < 3.15, "从未命名命名空间访问变量");

    // 练习 7: 解决名称冲突
    ASSERT(MyNamespace::value == 10, "显式访问 MyNamespace 的 value");
    ASSERT(Conflict::value == 20, "显式访问 Conflict 的 value");

    // 练习 8: 将特定成员引入作用域以解决歧义
    {
        using MyNamespace::value; // 将 MyNamespace::value 引入此作用域
        ASSERT(value == 10, "在特定 using 声明后访问 MyNamespace::value");
        ASSERT(Conflict::value == 20, "显式访问 Conflict::value");
    }
    {
        using namespace Conflict; // 将 Conflict 中的所有内容引入此作用域
        ASSERT(value == 20, "在使用 using 指令后访问 Conflict::value");
        ASSERT(MyNamespace::value == 10, "显式访问 MyNamespace::value");
        // ASSERT(MyNamespace::add(1,1) == 2, "显式访问 MyNamespace::add"); // 这仍然有效
    }

    return 0;
}




/*
`namespace`




代码解释
1. 基本命名空间访问
ASSERT(MyNamespace::value == 10, "从 MyNamespace 访问 value");
ASSERT(MyNamespace::add(5, 3) == 8, "从 MyNamespace 调用 add 函数");
使用 :: 作用域解析运算符访问命名空间成员。

2. using 声明
using MyNamespace::value;  // 只引入value成员
ASSERT(value == 10, "使用 using 声明后访问 value");
using 声明只引入指定的成员，其他成员仍需使用完整限定名。

3. using 指令
using namespace MyNamespace;  // 引入整个命名空间
ASSERT(value == 10, "在带有 using 指令的代码块内访问 value");
using namespace 引入整个命名空间的所有成员，但只在当前作用域有效。

4. 嵌套命名空间和别名
ASSERT(Outer::Inner::message == "Nested namespace", "从嵌套命名空间访问 message");
ASSERT(OIN::message == "Nested namespace", "使用命名空间别名访问 message");
可以使用完整路径或别名访问嵌套命名空间。

5. 未命名命名空间
ASSERT(pi > 3.14 && pi < 3.15, "从未命名命名空间访问变量");
未命名命名空间的成员在当前翻译单元内可直接访问。

6. 名称冲突解决
ASSERT(MyNamespace::value == 10, "显式访问 MyNamespace 的 value");
ASSERT(Conflict::value == 20, "显式访问 Conflict 的 value");
当名称冲突时，必须使用完整限定名来区分。

命名空间的最佳实践
1. 避免全局 using 指令
不好：

using namespace std;  // 在全局作用域，可能引起冲突
好：

// 在局部作用域使用
void func() {
    using namespace std;
    // 或者使用特定声明
    using std::cout;
    using std::endl;
}
2. 使用命名空间组织代码
namespace Math {
    namespace Constants {
        const double PI = 3.14159;
        const double E = 2.71828;
    }
    
    namespace Functions {
        double sin(double x) {  implementation  }
        double cos(double x) {  implementation  }
    }
}
3. 使用内联命名空间（C++11）
namespace Library {
    inline namespace v1 {
        void api() {  version 1  }
    }
    
    namespace v2 {
        void api() {  version 2  }
    }
}

// 默认使用v1版本
Library::api();  // 调用v1::api
Library::v2::api();  // 显式调用v2版本
4. 命名空间别名用于长命名空间
namespace very_long_namespace_name_that_is_annoying_to_type {
    // ...
}

namespace vln = very_long_namespace_name_that_is_annoying_to_type;
实际应用场景
1. 库开发
namespace MyLibrary {
    namespace Graphics {
        class Renderer {  ...  };
        class Texture {  ...  };
    }
    
    namespace Audio {
        class Sound {  ...  };
        class Music {  ...  };
    }
}
2. 版本控制
namespace MyApp {
    namespace v1 { /* 旧版本接口  }
    namespace v2 { /* 新版本接口  }
    
    using namespace v2;  // 默认使用最新版本
}
3. 模块化设计
namespace Database {
    namespace MySQL { /* MySQL实现  }
    namespace PostgreSQL { /* PostgreSQL实现  }
    namespace SQLite { /* SQLite实现  }
}
测试验证
程序运行后会通过所有测试：

命名空间基本访问正确
using声明和指令行为正确
嵌套命名空间和别名正确
名称冲突解决正确

*/